////////////////////////////////////////////////////////////////////////////////
// This file is part of the Mist compiler.                                    //
//                                                                            //
// Copyright (C) 2009 The Mist project                                        //
//                                                                            //
// For a list of contributors, see the COMMITTERS file.                       //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// in the COPYING file. If not, see <http://www.gnu.org/licenses/>.           //
////////////////////////////////////////////////////////////////////////////////

///
/// \file
/// Contains the Message class.
///

#ifndef MESSAGE_HPP
#define MESSAGE_HPP

////////////////////////////////////////////////////////////////////////////////
// Includes                                                                   //
////////////////////////////////////////////////////////////////////////////////

#include <string>
using std::string;

#include <vector>
using std::vector;

#include <set>
using std::set;

#include <boost/operators.hpp>
using boost::partially_ordered;
using boost::equality_comparable;

#include <boost/optional.hpp>
using boost::optional;

#include "messageinfo.hpp"
#include "location.hpp"
#include "common/ptr.hpp"
#include "common/string.hpp"
#include "common/outputproducer.hpp"

////////////////////////////////////////////////////////////////////////////////
// Message Class                                                              //
////////////////////////////////////////////////////////////////////////////////

/// An error or a warning generated by the compiler.
///
class Message : public OutputProducer {
	public:
		
		/// \return a new Message with code \a code and no location.
		///
		/// \pre <tt>the(MessageInfo).type(code) == NoLocation</tt>
		///
		static sptr<Message> construct(const string& code);
		
		/// \return a new Message with code \a code, no location and a parameter.
		///
		/// \pre <tt>the(MessageInfo).type(code) == NoLocation</tt>
		///
		static sptr<Message> construct(const string& code, const string& param1);
		
		/// \return a new Message with code \a code, no location and two parameters.
		///
		/// \pre <tt>the(MessageInfo).type(code) == NoLocation</tt>
		///
		static sptr<Message> construct(const string& code, const string& param1, const string& param2);
		
		/// \return a new Message with code \a code, no location and three parameters.
		///
		/// \pre <tt>the(MessageInfo).type(code) == NoLocation</tt>
		///
		static sptr<Message> construct(const string& code, const string& param1, const string& param2, const string& param3);
		
		/// \return a new Message with code \a code and location \a location.
		///
		/// \pre <tt>the(MessageInfo).type(code) == SingleLocation</tt>
		///
		static sptr<Message> construct(const string& code, const Location& location);
		
		/// \return a new Message with code \a code, location \a location and a parameter.
		///
		/// \pre <tt>the(MessageInfo).type(code) != NoLocation</tt>
		///
		static sptr<Message> construct(const string& code, const Location& location, const string& param1);
		
		/// \return a new Message with code \a code, location \a location and two parameters.
		///
		/// \pre <tt>the(MessageInfo).type(code) == SingleLocation</tt>
		///
		static sptr<Message> construct(const string& code, const Location& location, const string& param1, const string& param2);
		
		/// \return a new Message with code \a code, location \a location and three parameters.
		///
		/// \pre <tt>the(MessageInfo).type(code) == SingleLocation</tt>
		///
		static sptr<Message> construct(const string& code, const Location& location, const string& param1, const string& param2, const string& param3);
		
		/// \return the message, with parameters filled in
		///
		virtual string message() const =0;
		
		/// \return true , if this message can merge with the \a other message
		///         false, otherwise
		///
		virtual bool can_merge_with(sptr<Message> other) const =0;
		
		/// Merge this message with the \a other message.
		///
		/// \pre <tt>this->can_merge_with(other)</tt>
		///
		virtual void merge_with(sptr<Message> other) =0;
		
		/// Orders the messages by location, then by code.
		///
		virtual bool operator<(const Message& other) const =0;
		
		/// Send this message to output-stream \a out.
		///
		virtual ostream& send_to_stream(ostream& out) const =0;
		
		/// \return code of this message
		///
		string code() const;
	
	private:
		
		string _code;
};

#endif // MESSAGE_HPP
